#pragma once
#include <signal.h>
#include "complier.hpp"
#include "runner.hpp"
#include "../comm/log.hpp"
#include "../comm/expand_file_exist.hpp"
#include <jsoncpp/json/json.h>

using namespace Complier;
using namespace Runner;
using namespace Log;
using namespace expand;

// 根据错误码得出具体的错误信息描述
static std::string CodeToDes(int wrong_code, const std::string &file_name)
{
    if (wrong_code < 0)
    {
        if (-1 == wrong_code)
        {
            return "代码为空";
        }
        else if (-2 == wrong_code)
        {
            return "unknown error";
        }
        else if (-3 == wrong_code)
        {
            //编译错误
            std::string err_information;
            expand::Expand::readFromFile(expand::Expand::ComplieError(file_name), &err_information, true);
            return err_information;
        }
    }
    else if (wrong_code > 0)
    {
        //运行时报错
        if (wrong_code == SIGABRT)
            return "内存使用限制";
        else if (wrong_code == SIGXCPU)
            return "CPU资源限制";
        else if (wrong_code == SIGFPE)
            return "浮点数溢出";
        else if (wrong_code == SIGSEGV)
            return "段错误";
    }
    else
    {
        return "运行成功";
    }
    //运行成功
    return "unknow" + std::to_string(wrong_code); //如果错误未知，就继续添加
}



// 底层不保证文件名的唯一性，在这一层要进行处理，保证文件名的唯一性
namespace Run_Complie
{
    static void RemoveTempFile(const std::string& file_name)
    {
        //并不确定要清理多少文件,但是直接rm *file_name不就好了吗？
        std::string src_name = expand::Expand::Src(file_name);
        std::string complie_err_name = expand::Expand::ComplieError(file_name);
        std::string exe_name = expand::Expand::Exe(file_name);
        std::string stdin_name = expand::Expand::Stdin(file_name);
        std::string stdout_name = expand::Expand::Stdout(file_name);
        std::string stderr_name = expand::Expand::Stderror(file_name);
        if (FileExist::isFileExists(src_name))  unlink(src_name.c_str());
        if (FileExist::isFileExists(complie_err_name))  unlink(complie_err_name.c_str());
        if (FileExist::isFileExists(exe_name))  unlink(exe_name.c_str());
        if (FileExist::isFileExists(stdin_name))  unlink(stdin_name.c_str());
        if (FileExist::isFileExists(stdout_name))  unlink(stdout_name.c_str());
        if (FileExist::isFileExists(stderr_name))  unlink(stderr_name.c_str());
    }
    class run_complie
    {

    public:
        // 输入json：code, input, cpu_limit, mem_limit
        // 输出json: 状态码, 错误原因, 运行结果
        static void start(const std::string &in_json, std::string *out_json)
        {
            int wrong_code = 0, run_result = 0;
            std::string file_name;
            // 解析json串
            Json::Value in_value;
            Json::Value out_value;
            Json::Reader read;
            read.parse(in_json, in_value);
            // 提取
            std::string code = in_value["code"].asCString();
            std::string input = in_value["input"].asCString();
            int cpu_limit = in_value["cpu_limit"].asInt();
            int mem_limit = in_value["mem_limit"].asInt();
            if (code.size() == 0)
            {
                // 没有读取到信息
                wrong_code = -1;
                goto END;
            }

            // 构建唯一文件名
            file_name = expand::Expand::uniqueName();
            // 将代码写到temp目录下的特定文件
            if (!expand::Expand::writeToFile(expand::Expand::Src(file_name), code))
            {
                wrong_code = -2;
                logMessage(WARNING, "写入文件出错, %s, %d", __FILE__, __LINE__);
                goto END;
            }
            // 编译运行
            if (!Complier::Complier::complie(file_name))
            {
                wrong_code = -3;
                goto END;
            }
            run_result = Runner::runner::run(file_name, cpu_limit, mem_limit);
            if (run_result < 0)
            {
                wrong_code = -2;
                goto END;
            }
            else if (run_result > 0)
            {
                wrong_code = run_result;
                goto END;
            }
        END:
            out_value["status"] = wrong_code;
            out_value["reason"] = CodeToDes(wrong_code, file_name);
            if (0 == wrong_code)
            {
                // 全部成功
                std::string out_information, err_information;
                expand::Expand::readFromFile(expand::Expand::Stdout(file_name), &out_information, true);
                out_value["stdout"] = out_information;
                expand::Expand::readFromFile(expand::Expand::Stderror(file_name), &err_information, true);
                out_value["stderr"] = err_information;
            }
            // 序列化
            Json::StyledWriter writer;
            (*out_json) = writer.write(out_value);
            //清理所有临时文件
            RemoveTempFile(file_name);
        }
    };
}